/**
 * 滚动到底部
 * @param {string} el 滚轮所在元素
 */
function scrollToBottom(el) {
    clearInterval(window.T);
    window.T = setInterval(() => {
        const wapperHeight = el.scrollHeight != el.clientHeight ? el.clientHeight : el
        .offsetHeight; // 滚轮容器的可视高度
        const scrollSurplusHeight = el.scrollHeight - el.scrollTop; // 滚轮条剩余的高度
        const newScrollSurplusHeight = wapperHeight; // 滚动条应当预留的高度
        if (scrollSurplusHeight > newScrollSurplusHeight) {
            // 未滚动到预定位置
            const l = 1.1 ^ ((scrollSurplusHeight - newScrollSurplusHeight) / 10.0) + 2
            el.scrollTop += l;
            if ((scrollSurplusHeight - newScrollSurplusHeight) < l) {
                clearInterval(window.T);
            }
        } else {
            clearInterval(window.T);
        }
    }, 1);
}

/**
 * @param {Date|String} date 要格式化的时间
 * @param {Object} fmt 格式: Y是年，m是月，d是日，H是时，M是分，S是秒；字母的个数只影响是否使用0填充；
 * @return {String}
 */
function dateFormat(date, fmt) {
    if (Object.prototype.toString.call(date) !== '[object Date]') date = new Date(date)
    let ret;
    const opt = {
        "Y+": date.getFullYear().toString(),
        "m+": (date.getMonth() + 1).toString(),
        "d+": date.getDate().toString(),
        "H+": date.getHours().toString(),
        "M+": date.getMinutes().toString(),
        "S+": date.getSeconds().toString()
    };
    for (let k in opt) {
        ret = new RegExp("(" + k + ")").exec(fmt);
        if (ret) {
            fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
        };
    };
    return fmt;
}

/**
* 给指定元素设置loading
* 使用el.loading = false/true 来控制loading的显示
* @param {Object} el 元素对象
*/
function addLoading(el) {
    el.style.position = 'relative'
    const loadingEl = document.createElement('div')
    loadingEl.textContent = 'Loading ...'
    setInterval(function() { // 动画
        if (loadingEl.textContent.length == 11) {
            loadingEl.textContent = 'Loading '
        }
        loadingEl.textContent += '.'
    }, 500)
    loadingEl.style = 'display: none; align-items: center; justify-content: center; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; background-color: #d3d3d375;'
    el.loadingEl = loadingEl
    el.appendChild(loadingEl)
    Object.defineProperty(el, 'loading', {
        get: function() {
            return this._loading
        },
        set: function(val) {
            this._loading = val
            if (val) {
                el.loadingEl.style.display = 'flex'
            } else {
                el.loadingEl.style.display = 'none'
            }
        }
    })
}


/**
 * 获取上传组件
 */
function getUploadComp() {
    const confirmBoxEl = document.createElement("confirm-box")
    const confirmBoxHeaderEl = confirmBoxEl.appendChild(document.createElement("confirm-box-header"))
    confirmBoxHeaderEl.textContent = "文件上传/构建知识库"
    const confirmBoxBodyEl = confirmBoxEl.appendChild(document.createElement("confirm-box-body"))
    const uploadEl = confirmBoxBodyEl.appendChild(document.createElement("upload"))
    addLoading(uploadEl) // 加载loading

    const confirmBoxFooterEl = confirmBoxEl.appendChild(document.createElement("confirm-box-footer"))
    const buildEl = confirmBoxFooterEl.appendChild(document.createElement("button"))
    buildEl.textContent = "确认"
    // build按钮添加点击事件
    buildEl.addEventListener("click", async function(e) {
        uploadEl.loading = true
        const resp = await axios.post("/api/build", {
            buildList: uploadEl.filelist.map(m => m.remotePath),
        })
        const { code, data } = resp.data
        if (code == 200) {
            window.tip({message: "构建成功", type: "success"})
        } else {
            window.tip({message: "error", type: "error"})
        }
        uploadEl.loading = false
    })
    
    // 添加拖拽事件
    // 拖拽进入
    uploadEl.addEventListener( "dragenter" , async function (e) {
        e.preventDefault()
        e.stopPropagation()
    }, false )
    // 拖拽悬浮
    uploadEl.addEventListener( "dragover" , async function (e) {
        e.preventDefault()
        e.stopPropagation()
    }, false )
    // 拖拽离开
    uploadEl.addEventListener( "dragleave" , async function (e) {
        e.preventDefault()
        e.stopPropagation()
    }, false )
    // 拖拽放下
    uploadEl.addEventListener("drop", async function (e) {
        e.preventDefault()
        e.stopPropagation()
        const { dropEffect, files, items, types } = e.dataTransfer

        // 调用文件上传API
        uploadEl.loading = true
        const formdata = new FormData()
        for (const i in files) {
            formdata.append(`file${i}`, files[i])
        }
        const resp = await axios.post("/api/file_upload", formdata, {
            headers: {
                contentType: "multipart/form-data"
            }
        })
        const { code, data } = resp.data
        if (code == 200) {
            for (let f of files) {
                if (data[f.name]) {
                    f.remotePath = data[f.name]
                    uploadEl.filelist.push(f)
                }
            }
        } else {
            window.tip({message: "error", type: "error"})
        }
        uploadEl.loading = false
    })


    // 响应式加载文件列表
    uploadEl.filelist = []
    // 重写push方法
    uploadEl.filelist.push = function (...args) {
        this.__proto__.push.call(this, ...args)
        for (let item of args) {
            const { name } = item
            const intent = uploadEl.appendChild(document.createElement("filelist-item"))
            intent.file = item

            // 添加文件名文本
            const nameEl = document.createElement("div")
            nameEl.style = "margin: 0 1rem 0 0;"
            nameEl.textContent = name
            intent.appendChild(nameEl)
            // 添加删除按钮
            const deleteBTN = document.createElement("button")
            deleteBTN.textContent = '删除'
            deleteBTN.addEventListener("click", function(e) { // 删除文件
                uploadEl.filelist.splice(uploadEl.filelist.indexOf(intent.file), 1)
                intent.remove()
            })
            intent.appendChild(deleteBTN)
            scrollToBottom(uploadEl)
        }
    }
    return confirmBoxEl
}


window.log = window.console.log
window.addEventListener("load", function() {

    // 渲染聊天界面
    const chatViewsEls = document.getElementsByTagName("chat-views")
    for (let chatViews of chatViewsEls) {
        // 创建元素的组织架构
        const chatMsgViewsEl = document.createElement("chat-msg-views")
        
        // 新增聊天窗口顶部菜单栏目
        const chatMsgHeaderEl = chatMsgViewsEl.appendChild(document.createElement("chat-msg-header")) // 聊天窗口顶部容器创建
        const button1 = chatMsgHeaderEl.appendChild(document.createElement("button")) // 元素创建
        button1.textContent = "build"
        button1.addEventListener("click", async function() {
            window.popupEl.show("upload")
        })
        
        
        const chatMsgBodyEl = document.createElement("chat-msg-body")
        const chatMsgFooterEl = document.createElement("chat-msg-footer")
        const textareaPreEl = document.createElement("textarea-pre")
        const inputAssociationEl = document.createElement("input-association") // 输入联想框
        const textareaHindEl = document.createElement("textarea-hind")
        const textareaEl = document.createElement("textarea")
        const buttonEl = document.createElement("button")
        chatMsgViewsEl.appendChild(chatMsgBodyEl)
        chatMsgViewsEl.appendChild(chatMsgFooterEl)
        chatMsgFooterEl.appendChild(textareaPreEl)
        textareaPreEl.appendChild(inputAssociationEl)
        textareaPreEl.appendChild(textareaHindEl)
        textareaPreEl.appendChild(textareaEl)
        chatMsgFooterEl.appendChild(buttonEl)
        chatViews.appendChild(chatMsgViewsEl)

        // 设置输入联想元素的属性
        Object.defineProperty(inputAssociationEl, "items", { // 重写存取器
            set(val) {
                // 值类型判断
                if (Object.prototype.toString.call(val) != "[object Array]") throw new Error("not an array")
                // 有值才显示，没值隐藏联想框
                if (val.length > 0) {
                    this.setAttribute("show", "")
                    this.innerHTML = "" // 清空
                    for (let v of val) {
                        const item = this.appendChild(document.createElement("div"))
                        item.innerHTML = v
                        // 联想项点击事件
                        item.addEventListener("click", function() {
                            textareaEl.value = v
                            buttonEl.click()
                        })
                    }
                    this._items = val
                } else {
                    this.removeAttribute("show")
                }
            },
            get() {
                return this._items
            },
        })
        // 设置联想事件
        inputAssociationEl.onInputAssociation = async function(input) {
            inputAssociationEl.T = inputAssociationEl.T ? inputAssociationEl.T + 1 : 1
            const T = inputAssociationEl.T
            let resp = []
            if (input) {
                if (chatViews.onInputAssociation) { // 用户设置的联想的回调函数，参数是输入文本，返回一个文本数组
                    resp = await chatViews.onInputAssociation(input)
                }
            } else {
                resp = []
            }
            inputAssociationEl.items = resp
        }

        textareaEl.placeholder = "请输入（Enter发送，Shift+Enter换行）"
        textareaHindEl.textContent = textareaEl.placeholder // 文本域框架内容，支撑文本域高度随字量变化
        textareaEl.rows = 1
        // 设置文本域输入事件，监听行数，调整文本域高度适应
        textareaEl.addEventListener("input", async function() {
            // 文本域框架内容，支撑文本域高度随字量变化
            textareaHindEl.textContent = (this.value || textareaEl.placeholder) + " "
            // 根据输入框文本来控制发送按钮的状态
            if (this.value) { // 已输入
                buttonEl.removeAttribute("disabled") // 启用发送按钮
            } else { // 输入为空
                buttonEl.setAttribute("disabled", "") // 禁用发送按钮
            }
            // 触发输入联想
            inputAssociationEl.onInputAssociation(this.value)
        })
        // 输入框焦点事件
        textareaEl.addEventListener("focus", async function() {
            // 触发输入联想
            inputAssociationEl.onInputAssociation(this.value)
        })
        // 输入框丢失焦点事件
        textareaEl.addEventListener("blur", async function(e) {
            // 触发输入联想
            inputAssociationEl.onInputAssociation()
        })
        // 输入框的回车事件
        textareaEl.addEventListener("keydown", function(e) {
            if (e.keyCode == 13 && !e.shiftKey) {
                e.preventDefault() // 阻止默认事件，这是使文本输入
                buttonEl.click() // 触发发送按钮的点击事件
            }
        })

        buttonEl.textContent = '发送'
        buttonEl.setAttribute("disabled", "") // 默认禁用点击
        buttonEl.addEventListener("click", async function() { // 发送按钮的点击事件
            chatMsgBodyEl.messageList.push({
                html: textareaEl.value,
                owner: true,
                time: dateFormat(new Date(), "YY-mm-dd HH:MM:SS"),
            })
            const userinput = textareaEl.value // 临时保存用户输入
            textareaEl.value = ''
            textareaEl.dispatchEvent(new Event("input"))

            // 模拟回复
            let resp = "您好！机器人正在学习中！"
            if (chatViews.onMsgResponse) resp = await chatViews.onMsgResponse(userinput) // 调用回调方法，返回回复文本
            if (resp) {
                chatMsgBodyEl.messageList.push({
                    html: resp,
                    owner: false,
                    time: dateFormat(new Date(), "YY-mm-dd HH:MM:SS"),
                })
            }
        })

        // 设置消息列表，并重写push方法
        chatMsgBodyEl.messageList = []
        chatMsgBodyEl.messageList.push = function(...args) {
            this.__proto__.push.call(this, ...args)
            for (let item of args) {
                const msgIntentEl = document.createElement("msg-intent")
                const msgIntentIconEl = document.createElement("msg-intent-icon")
                const msgIntentContentEl = document.createElement("msg-intent-content")
                const msgIntentContentTimeEl = document.createElement("msg-intent-content-time")
                const msgIntentContentTextEl = document.createElement("msg-intent-content-text")
                const msgIntentContentTextHtmlEl = document.createElement("msg-intent-content-text-html")
                item.owner && msgIntentEl.setAttribute("owner", "")
                if (!item.owner) msgIntentIconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-hidden="true" width="100%" height="100%"><path d="M29.71,13.09A8.09,8.09,0,0,0,20.34,2.68a8.08,8.08,0,0,0-13.7,2.9A8.08,8.08,0,0,0,2.3,18.9,8,8,0,0,0,3,25.45a8.08,8.08,0,0,0,8.69,3.87,8,8,0,0,0,6,2.68,8.09,8.09,0,0,0,7.7-5.61,8,8,0,0,0,5.33-3.86A8.09,8.09,0,0,0,29.71,13.09Zm-12,16.82a6,6,0,0,1-3.84-1.39l.19-.11,6.37-3.68a1,1,0,0,0,.53-.91v-9l2.69,1.56a.08.08,0,0,1,.05.07v7.44A6,6,0,0,1,17.68,29.91ZM4.8,24.41a6,6,0,0,1-.71-4l.19.11,6.37,3.68a1,1,0,0,0,1,0l7.79-4.49V22.8a.09.09,0,0,1,0,.08L13,26.6A6,6,0,0,1,4.8,24.41ZM3.12,10.53A6,6,0,0,1,6.28,7.9v7.57a1,1,0,0,0,.51.9l7.75,4.47L11.85,22.4a.14.14,0,0,1-.09,0L5.32,18.68a6,6,0,0,1-2.2-8.18Zm22.13,5.14-7.78-4.52L20.16,9.6a.08.08,0,0,1,.09,0l6.44,3.72a6,6,0,0,1-.9,10.81V16.56A1.06,1.06,0,0,0,25.25,15.67Zm2.68-4-.19-.12-6.36-3.7a1,1,0,0,0-1.05,0l-7.78,4.49V9.2a.09.09,0,0,1,0-.09L19,5.4a6,6,0,0,1,8.91,6.21ZM11.08,17.15,8.38,15.6a.14.14,0,0,1-.05-.08V8.1a6,6,0,0,1,9.84-4.61L18,3.6,11.61,7.28a1,1,0,0,0-.53.91ZM12.54,14,16,12l3.47,2v4L16,20l-3.47-2Z" fill="currentColor"></path></svg>`
                else msgIntentIconEl.innerHTML = `<svg t="1688459733556" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2431" width="200" height="200"><path d="M508.8 141.21c119.85 0 217.36 97.51 217.36 217.36S628.65 575.93 508.8 575.93s-217.36-97.51-217.36-217.36 97.51-217.36 217.36-217.36m0-76.71c-162.41 0-294.07 131.66-294.07 294.07S346.39 652.64 508.8 652.64s294.07-131.66 294.07-294.07S671.21 64.5 508.8 64.5z" p-id="2432"></path><path d="M106.1 959.5c-2.21 0-4.46-0.19-6.71-0.59-20.86-3.68-34.79-23.58-31.11-44.44 38.81-219.89 255.93-338.54 440.52-338.54 21.18 0 38.36 17.17 38.36 38.36s-17.17 38.36-38.36 38.36c-122.34 0-329.6 74.7-364.97 275.17-3.28 18.59-19.47 31.68-37.73 31.68z" p-id="2433"></path><path d="M917.9 959.5c-18.27 0-34.45-13.09-37.73-31.7-35.38-200.46-242.64-275.16-364.97-275.16-21.18 0-38.36-17.17-38.36-38.36s17.17-38.36 38.36-38.36c184.59 0 401.72 118.65 440.52 338.54 3.68 20.86-10.25 40.76-31.11 44.44-2.25 0.41-4.5 0.6-6.71 0.6z" p-id="2434"></path></svg>`
                msgIntentContentTimeEl.textContent = item.time
                msgIntentContentTextHtmlEl.innerHTML = item.html
                chatMsgBodyEl.appendChild(msgIntentEl)
                msgIntentEl.appendChild(msgIntentIconEl)
                msgIntentEl.appendChild(msgIntentContentEl)
                msgIntentContentEl.appendChild(msgIntentContentTimeEl)
                msgIntentContentEl.appendChild(msgIntentContentTextEl)
                msgIntentContentTextEl.appendChild(msgIntentContentTextHtmlEl)
                // 滚动到最底部
                scrollToBottom(chatMsgBodyEl)
            }
        }
    }
})

/**
 * 创建全局弹窗
 * 显示弹窗：window.popupEl.show()
 * 设置弹窗关闭事件：this.closeEvents = []
 */
window.loadPopup = function() {
    window.popupEl = document.getElementsByTagName("body")[0].appendChild(document.createElement("pop-up"))
    window.popupEl.style.display = "none" // 默认隐藏
    // 关闭弹窗的事件
    window.popupEl.addEventListener("click", async function() {
        if (this.closeEvents) {
            // 用户设置的close事件组，只要有一个返回false就不关闭
            for (let closeEvent of this.closeEvents) {
                if (await closeEvent() === false) {
                    return
                }
            }
        }
        this.style.display = "none"
    })
    const popupBodyEl = window.popupEl.appendChild(document.createElement("pop-up-body")) // 创建弹窗内容主体
    popupBodyEl.addEventListener("click", function(e) {
        e.stopPropagation() // 阻止事件冒泡
    })
    // 显示弹窗的方法
    window.popupEl.show = function(name) {
        window.popupEl.style.display = "" // 显示弹窗
        popupBodyEl.innerHTML = ""
        if (window.popupEl.intents) popupBodyEl.appendChild(window.popupEl.intents[name])
    }
}
window.loadPopup() // 注册弹窗实例
window.popupEl.intents = {
    "upload": getUploadComp(),
}

/**
 * 简短消息提示方法
 * 使用方式：window.tip({message: "你好", type: "success"})
 */
window.tip = function({
    message,
    type,
    showTime,
}) {
    const tipEl = document.getElementsByTagName("body")[0].appendChild(document.createElement("tip"))
    if (type == "success") tipEl.style.color = "#2dd31a"
    if (type == "error") tipEl.style.color = "#d80003"
    tipEl.textContent = message
    setTimeout(function() {
        tipEl.remove()
    }, showTime || 3000)
}
// window.tip({message: "你好", type: "success"})


